package com.spring.theory.mvc;

import com.spring.theory.mvc.adapter.MyRequestMappingHandlerAdapter;
import com.spring.theory.mvc.adapter.resolver.TokenArgumentResolver;
import com.spring.theory.mvc.adapter.resolver.YmlReturnValueHandler;

import java.util.Collections;

import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

/**
 * WebConfig
 *
 * @author H
 * @version 1.0
 * @date 2024-01-11 14:55
 */
@Configuration
//默认扫描当前类所在包下的所有类及子类
@ComponentScan
//手动指定读取配置文件；@PropertySource注解通常用于指定属性配置文件的位置，但是它主要用于.properties文件
@PropertySource("classpath:application.properties")
//配置文件属性绑定
@EnableConfigurationProperties({WebMvcProperties.class, ServerProperties.class})
public class WebConfig {

    @Bean
    public ServletWebServerFactory servletWebServerFactory(ServerProperties serverProperties) {
        return new TomcatServletWebServerFactory(serverProperties.getPort());
    }

    /**
     * DispatcherServlet 由Spring创建，初始化在servlet容器中[onRefresh() 方法]
     */
    @Bean
    public DispatcherServlet dispatchServlet() {
        return new DispatcherServlet();
    }

    @Bean
    public DispatcherServletRegistrationBean servletRegistrationBean(DispatcherServlet dispatchServlet, WebMvcProperties webMvcProperties) {
        DispatcherServletRegistrationBean registrationBean = new DispatcherServletRegistrationBean(dispatchServlet, "/");
        //修改配置参数 loadOnStartUp 可以让DispatcherServlet在容器启动时加载，这样可以避免每次请求时才加载
        registrationBean.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
        return registrationBean;
    }

    /**
     * 解析 @RequestMapping 及其派生注解；在初始化时候，生成路径与控制器方法的映射关系
     * - 如果不显式添加bean，DispatcherServlet默认会自动注册RequestMappingHandlerMapping，但不放入bean工厂容器中，只会当作DispatcherServlet的属性
     */
    @Bean
    public RequestMappingHandlerMapping handlerMapping() {
        return new RequestMappingHandlerMapping();
    }

    /**
     * 调用requestHandlerMapping在chain中封装好的handlerMethod，执行对应的方法
     * 显式创建RequestMappingHandlerAdapter
     */
    @Bean
    public MyRequestMappingHandlerAdapter handlerAdapter() {
        MyRequestMappingHandlerAdapter handlerAdapter = new MyRequestMappingHandlerAdapter();
        //增加自定义参数解析器；Collections.singletonList方法返回的列表只有一个元素，并且这个列表是不可修改的
        handlerAdapter.setCustomArgumentResolvers(Collections.singletonList(new TokenArgumentResolver()));
        //增加自定义返回值参数解析器
        handlerAdapter.setCustomReturnValueHandlers(Collections.singletonList(new YmlReturnValueHandler()));
        return handlerAdapter;
    }


}
